package database.datastructure;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import database.DataFile;
import database.DataManager;
import database.Index;
import database.datastructure.ThresholdImpl.DecreasingOrderer;
import database.datastructure.ThresholdImpl.IncreasingOrderer;
import database.pojo.ConditionObj;

public class NaiveImpl {
	
	Map<String, Map<Integer,Integer>> sortedMap = new HashMap<String, Map<Integer,Integer>>();
	Map<String, List<Integer>> condListMap = new HashMap<String,List<Integer>>();
	TreeMap<Integer, Integer> resultMap = new TreeMap<Integer, Integer>();
	private ArrayList<String> attributes = null;
	private Map<String, Integer> conditionMap = new HashMap<String, Integer>();
	private ArrayList<Integer> topkRecordIds = null;
	private TreeMap<Integer, Integer> topkRecordIdMap = null;
	TreeMap<Integer, Integer> orderedMap = null;
	private boolean isDescending = false;
	private String tableName;	
	private boolean isWhere = false;
	private int topk = 0;
	int totalNoofRec = 0;
	
	public NaiveImpl(ConditionObj condObj) {
		Map<Integer, Map<String, String>> records = condObj.getRecords();
		String expression = condObj.getExpression();
		topk = condObj.getTopkValue();
		tableName = condObj.getTableName();
		ExpressionEval exprEval = new ExpressionEval();
		conditionMap = exprEval.evaluateExpression(expression);
		attributes = exprEval.getConditionAttr();			
		isWhere = condObj.isWhere();
		isDescending = condObj.isDescending();
		Iterator<String> attributesIter = attributes.iterator();
		try {
			if (isWhere) {
				while (attributesIter.hasNext()) {
					String curAttr = (String)attributesIter.next();
					BPlusTree bTree = new BPlusTree();
					for (int recordId: records.keySet()) {
						Map<String, String> record = records.get(recordId);
						bTree.insert(record.get(curAttr), recordId);
					}
					if (isDescending) {
						bTree.generateDecSortedList();
					} else {
						bTree.generateIncSortedList();
					}
					totalNoofRec = bTree.getSortedMap().size();
					sortedMap.put(curAttr, bTree.getSortedMap());
					condListMap.put(curAttr, bTree.getSortedValues());
				}
			} else {
				//System.out.println("Not where");
				DataManager dataMan = new DataManager();
				DataFile dataFile = dataMan.getFile(tableName);
				Map<String, String> columnIndexMap = dataFile.columnIndexMap;
				while (attributesIter.hasNext()) { 
					String curAttr = (String)attributesIter.next();
					if (columnIndexMap.containsKey(curAttr)) {
						try {
							//System.out.println(curAttr+" has Index");
							String usrIdxName = columnIndexMap.get(curAttr);
							//System.out.println("DataFile Name : "+dataFile.fileName);
							Index idx = dataFile.restoreIndex(usrIdxName);
							//System.out.println("User Index Name : "+usrIdxName);
							BPlusTree bTree = idx.getbTree();
							
							if (isDescending) {
								bTree.generateDecSortedList();
							} else {
								bTree.generateIncSortedList();
							}
							totalNoofRec = bTree.getSortedMap().size();
							sortedMap.put(curAttr, bTree.getSortedMap());
							condListMap.put(curAttr, bTree.getSortedValues());
						} catch(Exception e) {
							//e.printStackTrace();
						}
						
					} else {
					//	System.out.println(curAttr+" does not have Index");
						BPlusTree bTree = new BPlusTree();
						for (int recordId: records.keySet()) {
							Map<String, String> record = records.get(recordId);
							bTree.insert(record.get(curAttr), recordId);
						}
						if (isDescending) {
							bTree.generateDecSortedList();
						} else {
							bTree.generateIncSortedList();
						}
						totalNoofRec = bTree.getSortedMap().size();
						sortedMap.put(curAttr, bTree.getSortedMap());
						condListMap.put(curAttr, bTree.getSortedValues());
					}
				}
			}
			NaiveAlgorithm();
		} catch(Exception e) {
			//e.printStackTrace();
		}
	}
	
	public void NaiveAlgorithm() {
		int curRecNo = 0;
		//System.out.println("Total No of Records : "+totalNoofRec);
		while (curRecNo < totalNoofRec) {
			for (int i = 0; i < attributes.size(); i++) {
				String curAttr = attributes.get(i);
				List<Integer> recordIds= condListMap.get(curAttr);
				int curRecord = recordIds.get(curRecNo);
				Map<Integer, Integer> curMap = sortedMap.get(curAttr);
				int arg1 = Integer.parseInt((curMap.get(curRecord))+"");
				int arg2 = Integer.parseInt(conditionMap.get(curAttr)+"");
				int curValue = arg1 * arg2;

				ArrayList<String> secAttributes = new ArrayList<String>(attributes);
				secAttributes.remove(curAttr);
				for (int j = 0; j < secAttributes.size(); j++) {
					String remCurAttr = secAttributes.get(j);
					Map<Integer, Integer> remMap = sortedMap.get(remCurAttr);
					int arg11 = 0;
					if (remMap.get(curRecord) != null) 
						arg11 = Integer.parseInt((remMap.get(curRecord))+"");
					int arg12 = Integer.parseInt(conditionMap.get(remCurAttr) + "");
					curValue = curValue + arg11 * arg12;
				}
				resultMap.put(curRecord, curValue);
			}
			curRecNo++;
		}
		if (isDescending) {
			DecreasingOrderer decOrdr = new DecreasingOrderer(resultMap);
			orderedMap = new TreeMap(decOrdr);
			DecreasingOrderer decOrdrFin = new DecreasingOrderer(orderedMap);
			topkRecordIdMap = new TreeMap(decOrdrFin);
			
		}
		else {
			IncreasingOrderer incOrdr = new IncreasingOrderer(resultMap);
			orderedMap = new TreeMap(incOrdr);
			IncreasingOrderer incOrdrFin = new IncreasingOrderer(orderedMap);
			topkRecordIdMap = new TreeMap(incOrdrFin);
		}
		//System.out.println("Result Map Size : "+resultMap.size());
		
		int counter = 0;
		if (isDescending) {
			int startpos = (resultMap.size()-topk);
			for (Entry<Integer, Integer> e : resultMap.entrySet()) {
				if (counter >= startpos) {
					//System.out.println("<"+e.getKey()+", "+e.getValue()+">");
					orderedMap.put(e.getKey(), e.getValue());
					counter++;
				} else {
					counter++;
					continue;
				}
			}
		} else {
			for (Entry<Integer, Integer> e : resultMap.entrySet()) {
				if (counter == topk) {
					break;
				} else {
					orderedMap.put(e.getKey(), e.getValue());
					counter++;
				}
			}
		}
		
		
		try {
			
		} catch(Exception e) {
			
		}
		int breakPoint = 0;
		for (Integer recId : orderedMap.keySet()) {
			if (breakPoint == topk) {
				break;
			} else {
				topkRecordIdMap.put(recId, orderedMap.get(recId));
				breakPoint++;
			}
		}
	}
	
	public ArrayList<Integer> getTopkRecordIds() {
		return topkRecordIds;
	}

	public Map<Integer, Integer> getTopkRecordIdMap() {
		return topkRecordIdMap;
	}
	
	class IncreasingOrderer implements Comparator {
		
		Map incOrdrMap;
		IncreasingOrderer(Map tmpMap) {
			incOrdrMap = tmpMap;
		}
		
		@Override
		public int compare(Object arg0, Object arg1) {
			int returnValue = 0;
			try {
				if ((Integer)incOrdrMap.get(arg0) > (Integer)incOrdrMap.get(arg1))
					returnValue = 1;
				else if ((Integer)incOrdrMap.get(arg0) == (Integer)incOrdrMap.get(arg1))
					returnValue = 0;
				else 
					returnValue = -1;
			} catch(Exception e) {
				//e.printStackTrace();
			}
			return returnValue;
		}
		
	}
	
	class DecreasingOrderer implements Comparator {
		
		Map decOrdrMap;
		DecreasingOrderer(Map tmpMap) {
			decOrdrMap = tmpMap;
		}
		
		@Override
		public int compare(Object arg0, Object arg1) {
			int returnValue = 0;
			try {
				if ((Integer)decOrdrMap.get(arg0) < (Integer)decOrdrMap.get(arg1))
					returnValue = 1;
				else if ((Integer)decOrdrMap.get(arg0) == (Integer)decOrdrMap.get(arg1))
					returnValue = 0;
				else 
					returnValue = -1;
			} catch(Exception e) {
				//e.printStackTrace();
			}
			return returnValue;
		}
		
	}
}
